package jp.co.technotree.common.dao;

import java.math.BigDecimal;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.LinkedList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import jp.co.technotree.common.util.DBGLog;
import jp.co.technotree.exception.StatementParameterException;


public class StatementParser {
	private static String CLASSNAME=StatementParser.class.getName();
	private StatementMap[] statementMaps = null;
	private String sql = null;
	
	public StatementParser(String sql){
		String METHODNAME = "StatementParser";
		DBGLog.fwdebug(CLASSNAME,METHODNAME,"START");
				
		Pattern pattern = Pattern.compile("\\{:.*?\\}");
		Matcher matcher = pattern.matcher(sql);
		StringBuffer sb = new StringBuffer();
		int i=0;
		
		LinkedList<StatementMap> list = new LinkedList<StatementMap>();
		while (matcher.find()) {
			i++;	// i 1,2,3,・・・　１から開始
			String name = matcher.group();
			name = name.substring(2,name.length()-1);
			
			StatementMap map = new StatementMap(i,name);
			list.addLast(map);
			
			
			matcher.appendReplacement(sb, "?");
		}
		matcher.appendTail(sb);
		
		this.sql = sb.toString();
		//DBGLog.fwdebug(CLASSNAME,METHODNAME,"sql:"+this.sql);
		this.statementMaps = new StatementMap[list.size()];
		i=0;
		while ( list.size() > 0 ){
			this.statementMaps[i] = (StatementMap)list.removeFirst();
			//DBGLog.fwdebug(CLASSNAME,METHODNAME,"StatementMap["+this.statementMaps[i].getId()+"]:"+this.statementMaps[i].getName());
			i++;
		}
		
		DBGLog.fwdebug(CLASSNAME,METHODNAME,"END");
		
	}
	
	public String getSql(){
		return this.sql;
	}
	
	/**
	 * 
	 * @param preStmt
	 * @param params
	 * @throws StatementParameterException
	 */
	public void setParameters(PreparedStatement preStmt,StatementParameters params) throws StatementParameterException{
		String METHODNAME = "setParameters";
		DBGLog.fwdebug(CLASSNAME,METHODNAME,"START");
		int i;
		for ( i=0; i<this.statementMaps.length; i++ ){
			StatementMap map = this.statementMaps[i];
			StatementParameters.StatementParameter param = params.getParameter(map.getName());
			if ( param == null ){
				StatementParameterException exception = new StatementParameterException("項目["+map.getName()+"]に値が設定されていません。");
				throw exception;
			}
			try{
				switch(param.getType()){
				case StatementParameters.TYPE_STRING:
					String stringValue = (String)param.getValue();
					DBGLog.fwdebug(CLASSNAME,METHODNAME,"setString:"+param.getName()+" <- "+stringValue);
					preStmt.setString(map.getId(),stringValue);
					break;
				case StatementParameters.TYPE_STRINGFORMAT:
					String stringsValue[] = (String[])param.getValue();
					DBGLog.fwdebug(CLASSNAME,METHODNAME,"setStringFmt:"+param.getName()+" <- "+stringsValue[1]);
					preStmt.setString(map.getId(),stringsValue[1]);
					break;
				case StatementParameters.TYPE_INT:
					Integer intValue = (Integer)param.getValue();
					DBGLog.fwdebug(CLASSNAME,METHODNAME,"setInt:"+param.getName()+" <- "+intValue.intValue());
					preStmt.setInt(map.getId(),intValue.intValue());
					break;
				case StatementParameters.TYPE_LONG:
					Long longValue = (Long)param.getValue();
					DBGLog.fwdebug(CLASSNAME,METHODNAME,"setLong:"+param.getName()+" <- "+longValue.longValue());
					preStmt.setLong(map.getId(),longValue.longValue());
					
					break;
				case StatementParameters.TYPE_BIGDECIMAL:
					BigDecimal decimalValue = (BigDecimal)param.getValue();
					DBGLog.fwdebug(CLASSNAME,METHODNAME,"setBigDecimal:"+param.getName()+" <- "+decimalValue.toString());
					preStmt.setBigDecimal(map.getId(),decimalValue);
					break;
				case StatementParameters.TYPE_DATE:
					Date dateValue = (Date)param.getValue();
					DBGLog.fwdebug(CLASSNAME,METHODNAME,"setDate:"+param.getName()+" <- "+String.valueOf(dateValue));
					preStmt.setDate(map.getId(),dateValue);
					break;
				case StatementParameters.TYPE_TIME:
					Time timeValue = (Time)param.getValue();
					DBGLog.fwdebug(CLASSNAME,METHODNAME,"setTime:"+param.getName()+" <- "+String.valueOf(timeValue));
					preStmt.setTime(map.getId(),timeValue);
					break;
				case StatementParameters.TYPE_TIMESTAMP:
					Timestamp timestampValue = (Timestamp)param.getValue();
					DBGLog.fwdebug(CLASSNAME,METHODNAME,"setTimestamp:"+param.getName()+" <- "+String.valueOf(timestampValue));
					preStmt.setTimestamp(map.getId(),timestampValue);
					break;

				}
			}catch(SQLException e){
				e.printStackTrace();
				StatementParameterException exception = new StatementParameterException("SQLパラメータ設定エラー: id:"+map.getId()+" name:"+map.getName()+" type:"+param.getType());
				exception.addException(e);
				throw exception;
			}catch(Exception e){
				e.printStackTrace();
				StatementParameterException exception = new StatementParameterException("予期せぬエラー: LoopNo:["+i+"]\n項目情報:"+map.getId()+","+map.getName()+"\n"+e.getMessage());
				exception.addException(e);
				throw exception;
			}
		}
		DBGLog.fwdebug(CLASSNAME,METHODNAME,"END");
	}

}
